library IEEE;
   use IEEE.std_logic_1164.all;
   use IEEE.numeric_bit.all;

entity State_Graph is
  port(CLK,RST,Ready,N,Z,P: in bit;
       IR_out: in unsigned(15 downto 0);
       LD_MAR,LD_MDR,LD_IR,LD_BEN,LD_REG,LD_CC,LD_PC: out bit;
       GatePC,GateMDR,GateALU,GateMARMUX,GateSHF: out bit;
       PCMUX,DRMUX,ADDR2MUX,ALUK: out bit_vector(1 downto 0);
       REGMUX,ADDR1MUX,MARMUX,MIO_EN,R_W,DATA_SIZE,LSHF1: out bit;
       Current_State: out integer range 0 to 64;
       outputLED: out bit);
end State_Graph;

architecture Graph of State_Graph is

signal State,nState: integer range 0 to 64:=18;
--signal IR_out: unsigned (15 downto 0);
--signal Ready: bit;
signal Cntrl: bit_vector(26 downto 0);
signal BEN: bit:='0';

begin
Current_State <= State;
BEN <= (IR_out(11) and N) or (IR_out(10) and Z) or (IR_out(9) and P);
--------------
  LD_MAR <= Cntrl(26);
  LD_MDR <= Cntrl(25);
  LD_IR <= Cntrl(24);
  LD_BEN <= Cntrl(23);
  LD_REG <= Cntrl(22);
  LD_CC <= Cntrl(21);
  LD_PC <= Cntrl(20);
  GatePC <= Cntrl(19);
  GateMDR <= Cntrl(18);
  GateALU <= Cntrl(17);
  GateMARMUX <= Cntrl(16);
  GateSHF <= Cntrl(15);
  PCMUX <= Cntrl(14) & Cntrl(13);
  DRMUX <= Cntrl(12) & Cntrl(11);
  REGMUX <= Cntrl(10);
  ADDR1MUX <= Cntrl(9);
  ADDR2MUX <= Cntrl(8) & Cntrl(7);
  MARMUX <= Cntrl(6);
  ALUK <= Cntrl(5) & Cntrl(4);
  MIO_EN <= Cntrl(3);
  R_W <= Cntrl(2);
  DATA_SIZE <= Cntrl(1);
  LSHF1 <= Cntrl(0);

process(State)
   begin

       case State is
           when 0 =>
               if BEN = '1' then
                   nState <= 22;
               else
                   nState <= 18;
               end if;
               Cntrl <= "000000000000000000000000000";
           when 1 =>
               nState <= 18;
               Cntrl <= "000011000100000000000000000";
           when 2 =>
               nState <= 29;
               Cntrl <= "100000000010000001011000000";
           when 3 =>
               nState <= 24;
               Cntrl <= "100000000010000001011000000";
           when 4 =>
               if IR_out(11) = '1' then
                   nState <= 21;
               else
                   nState <= 20;
               end if;
               Cntrl <= "000000000000000000000000000";
           when 5 =>
               nState <= 18;
               Cntrl <= "000011000100000000000010000";
           when 6 =>
               nState <= 25;
               Cntrl <= "100000000010000001011000001";
           when 7 =>
               nState <= 23;
               Cntrl <= "100000000010000001011000001";
           --when 8 => -- RTI?
           when 9 =>
               nState <= 18;
               Cntrl <= "000011000100000000000100000";
           when 10 =>
               nState <= 18;
               Cntrl <= "000011000100000000000110000";
           when 11 =>
               if IR_out(7) = '1' then
                   nState <= 37;
               else
                   nState <= 36;
               end if;
               Cntrl <= "000000000000000010000000000";
           when 12 =>
               nState <= 18;
               Cntrl <= "000000100000100001000110000";
           when 13 =>
               nState <= 18;
               Cntrl <= "000011000001000000000000000";
           when 14 =>
               nState <= 18;
               Cntrl <= "000011000010000000101000001";
           when 15 =>
               nState <= 28;
               Cntrl <= "100000000010000000000000000";
           when 16 =>
               if Ready = '1' then
                   nState <= 18;
               else
                   nState <= 16;
               end if;
               Cntrl <= "000000000000000000000001110";
           when 17 =>
               if Ready = '1' then
                   nState <= 19;
               else
                   nState <= 17;
               end if;
               Cntrl <= "000000000000000000000001100";
           when 18|19 =>
               nState <= 34;
               Cntrl <= "100000010000000000000000000";
           when 20 =>
               nState <= 18;
               Cntrl <= "000010110000101001000000000";
           when 21 =>
               nState <= 18;
               Cntrl <= "000010110000101000110000001";
           when 22 =>
               nState <= 18;
               Cntrl <= "000000100000100000010000001";
           when 23 =>
               nState <= 16;
               Cntrl <= "010000000100000000000110010";
           when 24 =>
               nState <= 17;
               Cntrl <= "010000000100000000000110000";
           when 25 =>
               if Ready = '1' then
                   nState <= 27;
               else
                   nState <= 25;
               end if;
               Cntrl <= "010000000000000000000001010";
           when 27 =>
               nState <= 18;
               Cntrl <= "000011001000000000000000010";
           when 28 =>
               if Ready = '1' then
                   nState <= 30;
               else
                   nState <= 28;
               end if;
               Cntrl <= "010010010000001000000001010";
           when 29 =>
               if Ready = '1' then
                   nState <= 31;
               else
                   nState <= 29;
               end if;
               Cntrl <= "010000000000000000000001000";
           when 30 =>
               nState <= 18;
               Cntrl <= "000000101000010000000000010";
           when 31 =>
               nState <= 18;
               Cntrl <= "000011001000000000000000000";
           when 32 =>
               nState <= to_integer(IR_out(15 downto 12));
               Cntrl <= "000100000000000000000000000";
           when 33 =>
               if Ready = '1' then
                   nState <= 35;
               else
                   nState <= 33;
               end if;
               Cntrl <= "010000000000000000000001010";
           when 34 =>
               nState <= 33;
               Cntrl <= "000000100000000000000000000";    
           when 35 =>
               nState <= 32;
               Cntrl <= "001000001000000000000000010";
           when 36 =>
               nState <= 38;
               Cntrl <= "000010000000000110000000000";
           when 37 =>
               nState <= 39;
               Cntrl <= "100000000100000100000110000";
           when 38 =>
               nState <= 23;
               Cntrl <= "000000000000000110000000000";
           when 39 =>
               nState <= 25;
               Cntrl <= "100000000100000100000110000";
           when 40 =>
               nState <= 18;
               Cntrl <= "000000000000000000000000000";
           when others =>
               nState <= 0;
               Cntrl <= "000000000000000000000000000";
       end case;
   end process;

process(Clk,RST)
   begin
       if RST = '1' then
           State <= 40;
           outputLED <= '0';
       elsif Clk = '1' and Clk'event then
              State <= nState;
              --PC <= nPC;
       end if;
       if RST = '0' then
           outputLED <= '1';
       end if;
   end process;

end Graph;

